# gui.py
import sys
import os
import datetime
import asyncio
import json
from urllib.parse import urlparse

import tldextract
from PyQt5.QtWidgets import (
    QApplication, QWidget, QPushButton, QTextEdit, QVBoxLayout,
    QLabel, QLineEdit, QHBoxLayout, QMessageBox, QCheckBox, QFileDialog,
    QComboBox, QDialog, QDialogButtonBox, QGridLayout, QFrame, QButtonGroup, QRadioButton
)
from PyQt5.QtCore import QObject, pyqtSignal, Qt, QUrl, QRunnable, QThreadPool
from PyQt5.QtGui import QDesktopServices, QIcon
import requests
from automation import run_automation  # 确保自动化脚本已正确导入
from tools import generate_random_string


class EditTextDialog(QDialog):
    def __init__(self, title, placeholder, current_text="", parent=None):
        super().__init__(parent)
        self.setWindowTitle(title)
        self.resize(400, 300)

        layout = QVBoxLayout()

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText(placeholder)
        self.text_edit.setText(current_text)
        layout.addWidget(self.text_edit)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

        self.setLayout(layout)

    def get_text(self):
        return self.text_edit.toPlainText().strip()


class EditClashNodesDialog(QDialog):
    def __init__(self, current_nodes="", parent=None):
        super().__init__(parent)
        self.setWindowTitle("编辑 Clash 节点")
        self.resize(400, 300)

        layout = QVBoxLayout()

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("请输入 Clash 节点名称，每行一个")
        self.text_edit.setText(current_nodes)
        layout.addWidget(self.text_edit)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

        self.setLayout(layout)

    def get_nodes(self):
        return self.text_edit.toPlainText().strip()


class ClashProxyRotator:
    def __init__(self, api_url, selector_name, node_names):
        self.api_url = api_url  # e.g., "http://127.0.0.1:7890"
        self.selector_name = selector_name  # The name of the proxy group in Clash
        self.node_names = [{"name": name, "available": True} for name in node_names]
        self.current_node_index = 0

    def switch_to_next_proxy(self):
        success = False
        attempts = 0
        while not success and attempts < len(self.node_names):
            node_info = self.node_names[self.current_node_index]
            node_name = node_info["name"]
            if not node_info["available"]:
                # 如果当前节点不可用，跳到下一个
                self.current_node_index = (self.current_node_index + 1) % len(self.node_names)
                attempts += 1
                continue

            url = f"{self.api_url}/proxies/{self.selector_name}"
            data = {"name": node_name}
            try:
                response = requests.put(url, json=data)
                response.raise_for_status()

                if response.status_code == 204:
                    print(f"节点 {node_name} 已成功切换。")
                    success = True
                else:
                    print(f"节点 {node_name} 切换响应: {response.json()}")
                    success = True
            except requests.exceptions.RequestException as e:
                print(f"Request Exception: {e}")
                # 标记为不可用并尝试下一个代理
                self.node_names[self.current_node_index]["available"] = False

            self.current_node_index = (self.current_node_index + 1) % len(self.node_names)
            attempts += 1

        return {"success": success, "error": None if success else "所有代理尝试失败"}

    def is_any_proxy_available(self):
        """
        检查是否至少有一个代理是可用的
        """
        return any(node["available"] for node in self.node_names)

    def mark_current_proxy_unavailable(self):
        """
        标记当前代理为不可用
        """
        if self.node_names:
            current_proxy = self.node_names[self.current_node_index]
            current_proxy["available"] = False
            print(f"代理 {current_proxy['name']} 已被标记为不可用。")
            self.switch_to_next_proxy()
        else:
            print("代理列表为空，无法标记。")


class WorkerSignals(QObject):
    log = pyqtSignal(str, str)  # (identifier, message)
    finished = pyqtSignal(str, bool)  # (identifier, success)
    update_gui = pyqtSignal(list)


class WorkerRunnable(QRunnable):
    def __init__(self, config, line_str, identifier, proxy_rotator=None, chrome_path=None, parent=None):

        super().__init__()
        self.config = config
        self.line_str = line_str
        self.identifier = identifier
        self.proxy_rotator = proxy_rotator
        self.chrome_path = chrome_path
        self.signals = WorkerSignals()
        self._is_running = True
        self.task = None
        self.parent = parent

    def run(self):
        success = True

        def log_callback(message):
            nonlocal success
            if not self._is_running:
                return
            self.signals.log.emit(self.identifier, message)
            if "报错了保存下来" in message or "Failed" in message or "出错" in message:
                success = False

        # Clash 代理切换逻辑
        if self.config.get('proxy_type') == 'Clash代理' and self.proxy_rotator:
            # 切换到下一个代理节点
            switch_result = self.proxy_rotator.switch_to_next_proxy()
            if not switch_result['success']:
                self.signals.log.emit(self.identifier, f"切换代理失败: {switch_result['error']}")
                success = False
                self.signals.finished.emit(self.identifier, success)
                return
            else:
                self.signals.log.emit(
                    self.identifier,
                    f"已切换到代理节点: {self.proxy_rotator.node_names[self.proxy_rotator.current_node_index]['name']}"
                )

        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        try:
            self.task = loop.create_task(
                run_automation(self.config, self.line_str, log_callback, self.chrome_path, self))
            loop.run_until_complete(self.task)
        except asyncio.CancelledError:
            # 当任务被取消时，直接结束
            self.signals.log.emit(self.identifier, "任务已被停止。")
            success = False
        except Exception as e:
            self.signals.log.emit(self.identifier, f"An error occurred: {e}")
            success = False
        finally:
            loop.close()

        self.signals.finished.emit(self.identifier, success)

    def stop(self):
        self._is_running = False
        if self.task and not self.task.done():
            self.task.cancel()


class AppDemo(QWidget):
    def get_instance(self):
        return self
    def __init__(self):
        super().__init__()
        self.threadpool = QThreadPool()
        self.setWindowTitle('自动化测试工具')
        self.resize(800, 800)

        self.main_layout = QVBoxLayout()
        self.setup_ui()
        self.setup_connections()
        self.setLayout(self.main_layout)

        self.logs = []

        self.line_strs = []
        self.config = {}
        self.is_stopped = False

        self.clash_node_names = ""

        self.user_names = ""
        self.user_profiles = ""
        self.user_activities = ""
        self.user_activities_img = ""
        self.user_address = ""
        self.active_runnables = []

        self.user_avatar_images = ""
        self.user_background_images = ""

        self.config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')

        self.load_config_on_startup()
        self.check_expiration()

    def check_expiration(self):
        expiration_date = datetime.datetime(2025, 6, 3)
        current_date = datetime.datetime.now()
        if current_date > expiration_date:
            sys.exit()

    def add_spacing(self, height=10):
        spacer = QWidget()
        spacer.setFixedHeight(height)
        self.main_layout.addWidget(spacer)
    def setup_ui(self):
        # 验证码
        self.setup_api_key_section()
        # 浏览器窗口配置
        self.setup_chrome_browser_section()
        self.setup_bit_browser_section()
        self.add_spacing()
        # 注册详情配置
        self.setup_quick_reg_section()
        # 搜索用户
        self.setup_search_user_section()
        self.setup_edit_buttons_section()
        self.setup_upload_image_section()
        self.add_spacing()
        # 代理设置
        self.setup_proxy_selection_section()
        self.setup_save_location_section()
        self.add_spacing()
        # 邮箱
        self.setup_email_list_section()
        self.setup_log_display_section()
        self.setup_control_buttons_section()
        self.setup_internal_use_label()

    def update_gui_content(self, line_strs):
        """更新GUI内容的槽函数"""
        try:
            self.line_str_input.setText('\n'.join(line_strs))
        except Exception as e:
            print(f"更新GUI内容时出错: {e}")
    def setup_api_key_section(self):
        yes_api_key_layout = QHBoxLayout()

        # 添加本地打码和API打码的单选按钮
        self.captcha_group = QButtonGroup(self)
        self.local_captcha_radio = QRadioButton("本地打码")
        self.api_captcha_radio = QRadioButton("API打码")
        self.captcha_group.addButton(self.local_captcha_radio)
        self.captcha_group.addButton(self.api_captcha_radio)
        self.local_captcha_radio.setChecked(True)  # 默认选择本地打码

        yes_api_key_layout.addWidget(self.local_captcha_radio)
        yes_api_key_layout.addWidget(self.api_captcha_radio)

        # API Key 输入框
        yes_api_key_label = QLabel("API Key:")
        self.yes_api_key_input = QLineEdit()
        self.yes_api_key_input.setEnabled(False)  # 默认禁用
        yes_api_key_layout.addWidget(yes_api_key_label)
        yes_api_key_layout.addWidget(self.yes_api_key_input)

        # 获取key按钮
        self.get_key_button = QPushButton("获取key")
        self.get_key_button.setEnabled(False)  # 默认禁用
        yes_api_key_layout.addWidget(self.get_key_button)

        self.main_layout.addLayout(yes_api_key_layout)
        # 连接信号
        self.api_captcha_radio.toggled.connect(self.toggle_api_options)
    def setup_chrome_browser_section(self):
        chrome_browser_layout = QHBoxLayout()
        self.use_chrome_checkbox = QCheckBox("使用系统 Chrome 浏览器")
        chrome_browser_layout.addWidget(self.use_chrome_checkbox)

        self.chrome_path_input = QLineEdit()
        self.chrome_path_input.setDisabled(True)
        chrome_browser_layout.addWidget(QLabel("Chrome 路径:"))
        chrome_browser_layout.addWidget(self.chrome_path_input)

        self.browse_chrome_button = QPushButton("浏览")
        self.browse_chrome_button.setDisabled(True)
        chrome_browser_layout.addWidget(self.browse_chrome_button)

        self.main_layout.addLayout(chrome_browser_layout)

    def setup_bit_browser_section(self):
        browser_layout = QHBoxLayout()
        self.use_bit_checkbox = QCheckBox("使用 Bit 浏览器")
        browser_layout.addWidget(self.use_bit_checkbox)

        self.port_input = QLineEdit()
        self.port_input.setText("54345")
        self.port_input.setDisabled(True)
        browser_layout.addWidget(QLabel("端口号"))
        browser_layout.addWidget(self.port_input)

        window_count_label = QLabel("窗口数量:")
        self.window_count_combo = QComboBox()
        self.window_count_combo.addItems([str(i) for i in range(1, 11)])
        browser_layout.addWidget(window_count_label)
        browser_layout.addWidget(self.window_count_combo)
        self.main_layout.addLayout(browser_layout)

    def setup_quick_reg_section(self):
        quick_reg_layout = QHBoxLayout()
        self.quick_reg_checkbox = QCheckBox("快速注册")
        quick_reg_layout.addWidget(self.quick_reg_checkbox)

        self.send_msg_checkbox = QCheckBox("是否发送消息")
        quick_reg_layout.addWidget(self.send_msg_checkbox)

        send_msg_label = QLabel("发送条数:")
        send_msg_label.setFixedWidth(60)
        quick_reg_layout.addWidget(send_msg_label)

        self.num_msgs_combo = QComboBox()
        self.num_msgs_combo.addItems([str(i) for i in range(1, 11)])
        self.num_msgs_combo.setDisabled(True)
        quick_reg_layout.addWidget(self.num_msgs_combo)

        self.main_layout.addLayout(quick_reg_layout)

    def setup_search_user_section(self):
        search_user_layout = QVBoxLayout()

        # 创建一个水平布局来包含所有控件
        controls_layout = QHBoxLayout()

        # 添加复选框
        self.search_user_checkbox = QCheckBox("启用搜索用户")
        controls_layout.addWidget(self.search_user_checkbox)

        # 添加搜索内容
        controls_layout.addWidget(QLabel("搜索内容:"))
        self.browse_users_name = QLineEdit()
        self.browse_users_name.setPlaceholderText("输入内容")
        self.browse_users_name.setEnabled(False)
        controls_layout.addWidget(self.browse_users_name)

        # 添加浏览个数
        controls_layout.addWidget(QLabel("浏览个数:"))
        self.browse_users_count = QComboBox()
        self.browse_users_count.addItems([str(i) for i in range(0, 15)])
        self.browse_users_count.setEnabled(False)
        controls_layout.addWidget(self.browse_users_count)

        # 添加浏览次数
        controls_layout.addWidget(QLabel("浏览次数:"))
        self.browse_times = QComboBox()
        self.browse_times.addItems([str(i) for i in range(1, 11)])
        self.browse_times.setEnabled(False)
        controls_layout.addWidget(self.browse_times)

        # 添加浏览时长
        controls_layout.addWidget(QLabel("浏览时长(秒):"))
        self.browse_duration = QComboBox()
        self.browse_duration.addItems([str(i) for i in range(1, 11)])
        self.browse_duration.setEnabled(False)
        controls_layout.addWidget(self.browse_duration)

        search_user_layout.addLayout(controls_layout)
        self.main_layout.addLayout(search_user_layout)

    def edit_avatar_images(self):
        dialog = EditTextDialog(
            title="编辑头像图片",
            placeholder="请输入头像图片路径，每行一个",
            current_text=self.user_avatar_images,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_avatar_images = dialog.get_text()
            self.avatar_button.setText("编辑头像（已编辑）")
            print(f"头像图片已更新: {self.user_avatar_images}")

    def edit_background_images(self):
        dialog = EditTextDialog(
            title="编辑背景图片",
            placeholder="请输入背景图片路径，每行一个",
            current_text=self.user_background_images,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_background_images = dialog.get_text()
            self.background_button.setText("编辑背景图（已编辑）")
            print(f"背景图片已更新: {self.user_background_images}")

    def setup_edit_buttons_section(self):
        edit_name_buttons_layout = QHBoxLayout()
        edit_buttons_layout = QHBoxLayout()

        self.name_button = QPushButton("编辑姓名")
        edit_name_buttons_layout.addWidget(self.name_button)

        self.name_suffix_checkbox = QCheckBox("添加姓名后缀")
        edit_name_buttons_layout.addWidget(self.name_suffix_checkbox)

        self.suffix_content_input = QLineEdit()
        self.suffix_content_input.setPlaceholderText("后缀内容（留空随机生成）")
        self.suffix_content_input.setEnabled(False)
        edit_name_buttons_layout.addWidget(self.suffix_content_input)

        self.suffix_length_input = QLineEdit()
        self.suffix_length_input.setPlaceholderText("随机位数（默认4位）")
        self.suffix_length_input.setEnabled(False)
        self.suffix_length_input.setFixedWidth(200)
        edit_name_buttons_layout.addWidget(self.suffix_length_input)

        # 添加动态开关
        activity_layout = QHBoxLayout()
        self.activity_checkbox = QCheckBox("启用动态")
        activity_layout.addWidget(self.activity_checkbox)
        self.activity_button = QPushButton("编辑动态")
        self.activity_button.setEnabled(False)  # 默认禁用
        activity_layout.addWidget(self.activity_button)

        # 添加动态图片开关
        self.activity_img_checkbox = QCheckBox("启用动态图片")
        activity_layout.addWidget(self.activity_img_checkbox)
        self.activity_img_button = QPushButton("编辑动态图片")
        self.activity_img_button.setEnabled(False)  # 默认禁用
        activity_layout.addWidget(self.activity_img_button)

        self.profile_button = QPushButton("编辑简介")
        activity_layout.addWidget(self.profile_button)

        self.address_button = QPushButton("编辑地址")
        activity_layout.addWidget(self.address_button)

        self.main_layout.addLayout(edit_name_buttons_layout)
        self.main_layout.addLayout(activity_layout)
        self.main_layout.addLayout(edit_buttons_layout)

    def setup_upload_image_section(self):
        # 头像上传部分
        avatar_layout = QHBoxLayout()
        self.upload_avatar_checkbox = QCheckBox("启用上传头像")
        avatar_layout.addWidget(self.upload_avatar_checkbox)

        self.avatar_button = QPushButton("编辑头像")
        self.avatar_button.setEnabled(False)
        avatar_layout.addWidget(self.avatar_button)

        # 背景图上传部分
        # background_layout = QHBoxLayout()
        self.upload_background_checkbox = QCheckBox("启用上传背景图")
        avatar_layout.addWidget(self.upload_background_checkbox)

        self.background_button = QPushButton("编辑背景图")
        self.background_button.setEnabled(False)
        avatar_layout.addWidget(self.background_button)

        # 添加到主布局
        upload_layout = QVBoxLayout()
        upload_layout.addLayout(avatar_layout)
        # upload_layout.addLayout(background_layout)
        self.main_layout.addLayout(upload_layout)

    # def setup_window_count_section(self):
    #     window_count_layout = QHBoxLayout()
    #     window_count_label = QLabel("窗口数量:")
    #     self.window_count_combo = QComboBox()
    #     self.window_count_combo.addItems([str(i) for i in range(1, 11)])
    #     window_count_layout.addWidget(window_count_label)
    #     window_count_layout.addWidget(self.window_count_combo)
    #     self.main_layout.addLayout(window_count_layout)

    def setup_proxy_selection_section(self):
        proxy_layout = QVBoxLayout()
        proxy_option_layout = QHBoxLayout()

        proxy_label = QLabel("代理选择:")
        proxy_option_layout.addWidget(proxy_label)

        self.proxy_combo = QComboBox()
        self.proxy_combo.addItems(['本地代理', 'Clash代理'])
        proxy_option_layout.addWidget(self.proxy_combo)

        proxy_layout.addLayout(proxy_option_layout)

        self.clash_settings_layout = QHBoxLayout()
        self.clash_port_label = QLabel("端口号:")
        self.clash_settings_layout.addWidget(self.clash_port_label)

        self.clash_port_input = QLineEdit()
        self.clash_port_input.setText("7890")
        self.clash_settings_layout.addWidget(self.clash_port_input)

        self.edit_clash_nodes_button = QPushButton("编辑 Clash 节点")
        self.clash_settings_layout.addWidget(self.edit_clash_nodes_button)

        self.switch_frequency_label = QLabel("切换频率:")
        self.clash_settings_layout.addWidget(self.switch_frequency_label)

        self.switch_frequency_input = QLineEdit()
        self.switch_frequency_input.setText("5")
        self.switch_frequency_input.setFixedWidth(50)
        self.switch_frequency_input.setPlaceholderText("频率")
        self.clash_settings_layout.addWidget(self.switch_frequency_input)

        self.proxy_rule_label = QLabel("代理规则:")
        self.clash_settings_layout.addWidget(self.proxy_rule_label)

        self.proxy_rule_combo = QComboBox()
        self.proxy_rule_combo.addItems(['Proxy', 'Global'])
        self.clash_settings_layout.addWidget(self.proxy_rule_combo)

        self.clash_port_label.hide()
        self.clash_port_input.hide()
        self.edit_clash_nodes_button.hide()
        self.switch_frequency_label.hide()
        self.switch_frequency_input.hide()
        self.proxy_rule_label.hide()
        self.proxy_rule_combo.hide()

        proxy_layout.addLayout(self.clash_settings_layout)
        self.main_layout.addLayout(proxy_layout)

    def toggle_suffix_options(self, state):
        if state == Qt.Checked:
            self.suffix_content_input.setEnabled(True)
            self.suffix_length_input.setEnabled(True)
        else:
            self.suffix_content_input.setEnabled(False)
            self.suffix_length_input.setEnabled(False)
            self.suffix_content_input.clear()
            self.suffix_length_input.clear()

    def toggle_avatar_button(self, state):
        self.avatar_button.setEnabled(state)
    def toggle_background_button(self, state):
        self.background_button.setEnabled(state)
    def toggle_activity_button(self, state):
        self.activity_button.setEnabled(state)
    def toggle_activity_img_button(self, state):
        self.activity_img_button.setEnabled(state)
    def toggle_search_user_options(self, state):
        self.browse_users_count.setEnabled(state)
        self.browse_users_name.setEnabled(state)
        self.browse_times.setEnabled(state)
        self.browse_duration.setEnabled(state)

    def toggle_api_options(self, checked):
        self.yes_api_key_input.setEnabled(checked)
    def setup_save_location_section(self):
        save_location_layout = QHBoxLayout()
        save_location_label = QLabel("保存位置:")
        self.save_location_input = QLineEdit()
        self.save_location_input.setReadOnly(True)
        save_location_layout.addWidget(save_location_label)
        save_location_layout.addWidget(self.save_location_input)

        self.browse_save_location_button = QPushButton("选择文件夹")
        save_location_layout.addWidget(self.browse_save_location_button)

        self.open_folder_button = QPushButton("打开文件夹")
        save_location_layout.addWidget(self.open_folder_button)

        self.main_layout.addLayout(save_location_layout)

    def setup_email_list_section(self):
        email_section_layout = QVBoxLayout()

        # 添加邮箱类型选择
        email_type_layout = QHBoxLayout()
        email_type_label = QLabel("邮箱类型:")
        self.email_type_combo = QComboBox()
        self.email_type_combo.addItems(['Outlook', '自建邮箱', 'Firstmail'])
        email_type_layout.addWidget(email_type_label)
        email_type_layout.addWidget(self.email_type_combo)
        email_section_layout.addLayout(email_type_layout)

        # 自建邮箱配置框
        self.custom_email_config = QWidget()
        custom_email_layout = QGridLayout()

        # 添加配置项
        # 添加token配置项

        custom_email_layout.addWidget(QLabel("Token:"), 3, 0)
        self.token_input = QLineEdit()
        custom_email_layout.addWidget(self.token_input, 3, 1)

        # 添加默认密码配置项
        custom_email_layout.addWidget(QLabel("默认密码:"), 4, 0)

        self.default_password_input = QLineEdit()
        self.default_password_input.setPlaceholderText("不填则随机生成")
        custom_email_layout.addWidget(self.default_password_input, 4, 1)

        custom_email_layout.addWidget(QLabel("任务总数:"), 5, 0)
        self.total_count_input = QLineEdit()
        self.total_count_input.setPlaceholderText("创建邮箱数量/运行次数")
        self.total_count_input.setText("1000")
        custom_email_layout.addWidget(self.total_count_input, 5, 1)

        custom_email_layout.addWidget(QLabel("邮箱域名:(例如 http://mail.xxx.com)"), 6, 0)
        self.email_host_input = QLineEdit()
        self.email_host_input.setPlaceholderText("例如 http://mail.xxx.com")
        custom_email_layout.addWidget(self.email_host_input, 6, 1)

        custom_email_layout.addWidget(QLabel("pop3 域名/ip :"), 7, 0)
        self.email_pop_host_input = QLineEdit()
        self.email_pop_host_input.setPlaceholderText("例如 http://pop3.xxx.com 或者 http://11.11.11.11")
        custom_email_layout.addWidget(self.email_pop_host_input, 7, 1)

        custom_email_layout.addWidget(QLabel("pop3 端口:(例如 110)"), 8, 0)
        self.email_pop_prot_input = QLineEdit()
        self.email_pop_prot_input.setPlaceholderText("例如 110")
        custom_email_layout.addWidget(self.email_pop_prot_input, 8, 1)

        self.custom_email_config.setLayout(custom_email_layout)
        self.custom_email_config.hide()  # 默认隐藏
        email_section_layout.addWidget(self.custom_email_config)

        # 邮箱列表
        self.line_str_label = QLabel("邮箱列表:")
        self.line_str_input = QTextEdit()
        self.line_str_input.setFixedHeight(150)
        self.line_str_input.setPlaceholderText(
            "请输入邮箱，每行一个，格式为 'email----password----client_id----token'"
        )
        email_section_layout.addWidget(self.line_str_label)
        email_section_layout.addWidget(self.line_str_input)

        self.main_layout.addLayout(email_section_layout)

        # 连接信号
        self.email_type_combo.currentIndexChanged.connect(self.on_email_type_changed)

    def setup_control_buttons_section(self):
        button_layout = QHBoxLayout()
        self.start_button = QPushButton('开始测试')
        button_layout.addWidget(self.start_button)

        self.stop_button = QPushButton('停止测试')
        self.stop_button.setEnabled(False)
        button_layout.addWidget(self.stop_button)

        # 添加导出未注册账号按钮
        self.export_button = QPushButton('导出未注册账号')
        button_layout.addWidget(self.export_button)

        self.main_layout.addLayout(button_layout)

    def setup_log_display_section(self):
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.main_layout.addWidget(self.log_text)

    def setup_internal_use_label(self):
        internal_use_layout = QHBoxLayout()
        internal_use_layout.addStretch()
        internal_use_label = QLabel("此程序仅供自动化测试学习使用，请勿非法使用，定制软件联系飞机：@tui999888")
        internal_use_label.setStyleSheet("color: gray; font-size: 10px;")
        internal_use_layout.addWidget(internal_use_label)
        self.main_layout.addLayout(internal_use_layout)

    def setup_connections(self):
        self.api_captcha_radio.toggled.connect(self.toggle_api_options)
        self.get_key_button.clicked.connect(self.open_get_key_url)
        self.use_chrome_checkbox.stateChanged.connect(self.toggle_chrome_options)
        self.browse_chrome_button.clicked.connect(self.browse_chrome_path)
        self.use_bit_checkbox.stateChanged.connect(self.toggle_bit_options)
        self.quick_reg_checkbox.stateChanged.connect(self.on_quick_reg_changed)
        self.send_msg_checkbox.stateChanged.connect(self.toggle_msg_options)
        self.browse_save_location_button.clicked.connect(self.browse_save_location)
        self.open_folder_button.clicked.connect(self.open_save_location)
        self.proxy_combo.currentIndexChanged.connect(self.on_proxy_selection_changed)
        self.edit_clash_nodes_button.clicked.connect(self.edit_clash_nodes)
        self.name_button.clicked.connect(self.edit_name)
        self.profile_button.clicked.connect(self.edit_profile)
        self.activity_button.clicked.connect(self.edit_activity)
        self.activity_img_button.clicked.connect(self.edit_activity_img)
        self.address_button.clicked.connect(self.edit_address)
        self.start_button.clicked.connect(self.start_test)
        self.stop_button.clicked.connect(self.stop_test)
        self.name_suffix_checkbox.stateChanged.connect(self.toggle_suffix_options)

        self.activity_checkbox.stateChanged.connect(self.toggle_activity_button)
        self.activity_img_checkbox.stateChanged.connect(self.toggle_activity_img_button)
        self.search_user_checkbox.stateChanged.connect(self.toggle_search_user_options)

        self.upload_avatar_checkbox.stateChanged.connect(self.toggle_avatar_button)
        self.upload_background_checkbox.stateChanged.connect(self.toggle_background_button)
        self.avatar_button.clicked.connect(self.edit_avatar_images)
        self.background_button.clicked.connect(self.edit_background_images)
        self.export_button.clicked.connect(self.export_unregistered_accounts)

    def open_get_key_url(self):
        QDesktopServices.openUrl(QUrl("https://yescaptcha.com/i/xUOZlk"))

    def toggle_chrome_options(self, state):
        if state == Qt.Checked:
            self.use_bit_checkbox.setChecked(False)
            self.chrome_path_input.setDisabled(False)
            self.browse_chrome_button.setDisabled(False)
            self.port_input.setDisabled(True)
        else:
            self.chrome_path_input.setDisabled(True)
            self.browse_chrome_button.setDisabled(True)

    def toggle_bit_options(self, state):
        if state == Qt.Checked:
            self.use_chrome_checkbox.setChecked(False)
            self.port_input.setDisabled(False)
            self.chrome_path_input.setDisabled(True)
            self.browse_chrome_button.setDisabled(True)
        else:
            self.port_input.setDisabled(True)

    def export_unregistered_accounts(self):
        if not self.line_strs:
            QMessageBox.warning(self, "提示", "没有可导出的账号")
            return

        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getSaveFileName(
            self,
            "导出未注册账号",
            "",
            "Text Files (*.txt);;All Files (*)",
            options=options
        )

        if file_name:
            try:
                with open(file_name, 'w', encoding='utf-8') as f:
                    for line in self.line_strs:
                        f.write(f"{line}\n")
                QMessageBox.information(self, "成功", "未注册账号导出成功！")
            except Exception as e:
                QMessageBox.critical(self, "错误", f"导出失败：{str(e)}")
    def on_quick_reg_changed(self, state):
        if state == Qt.Checked:
            self.send_msg_checkbox.setChecked(False)
            self.send_msg_checkbox.setDisabled(True)
            self.upload_avatar_checkbox.setChecked(False)
            self.upload_avatar_checkbox.setDisabled(True)
            self.upload_background_checkbox.setChecked(False)
            self.upload_background_checkbox.setDisabled(True)
        else:
            self.send_msg_checkbox.setDisabled(False)
            self.upload_avatar_checkbox.setDisabled(False)
            self.upload_background_checkbox.setDisabled(False)

    def toggle_msg_options(self, state):
        if state == Qt.Checked:
            self.num_msgs_combo.setDisabled(False)
        else:
            self.num_msgs_combo.setDisabled(True)

    def browse_save_location(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        folder = QFileDialog.getExistingDirectory(self, "选择保存位置", options=options)
        if folder:
            self.save_location_input.setText(folder)
            print(f"保存位置已设置为: {folder}")

    def open_save_location(self):
        folder = self.save_location_input.text().strip()
        if folder and os.path.exists(folder):
            QDesktopServices.openUrl(QUrl.fromLocalFile(folder))
        else:
            QMessageBox.warning(self, "路径错误", "请选择有效的文件夹路径。")

    def browse_chrome_path(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择 Chrome 浏览器可执行文件", "", "Chrome 可执行文件 (chrome.exe);;所有文件 (*)", options=options
        )
        if file_path:
            self.chrome_path_input.setText(file_path)

    def on_proxy_selection_changed(self, index):
        proxy_type = self.proxy_combo.currentText()
        if proxy_type == 'Clash代理':
            self.clash_port_label.show()
            self.clash_port_input.show()
            self.edit_clash_nodes_button.show()
            self.switch_frequency_label.show()
            self.switch_frequency_input.show()
            self.proxy_rule_label.show()
            self.proxy_rule_combo.show()
        else:
            self.clash_port_label.hide()
            self.clash_port_input.hide()
            self.edit_clash_nodes_button.hide()
            self.switch_frequency_label.hide()
            self.switch_frequency_input.hide()
            self.proxy_rule_label.hide()
            self.proxy_rule_combo.hide()

    def edit_clash_nodes(self):
        dialog = EditClashNodesDialog(current_nodes=self.clash_node_names, parent=self)
        if dialog.exec_() == QDialog.Accepted:
            self.clash_node_names = dialog.get_nodes()
            self.edit_clash_nodes_button.setText("编辑 Clash 节点（已编辑）")
            print(f"Clash 节点已更新: {self.clash_node_names}")

    def edit_name(self):
        dialog = EditTextDialog(
            title="编辑姓名",
            placeholder="请输入姓名，每行一个, firstname----lastname",
            current_text=self.user_names,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_names = dialog.get_text()
            self.name_button.setText("编辑姓名（已编辑）")
            print(f"姓名已更新: {self.user_names}")

    def edit_profile(self):
        dialog = EditTextDialog(
            title="编辑简介",
            placeholder="请输入简介，每行一个",
            current_text=self.user_profiles,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_profiles = dialog.get_text()
            self.profile_button.setText("编辑简介（已编辑）")
            print(f"简介已更新: {self.user_profiles}")

    def edit_activity(self):
        dialog = EditTextDialog(
            title="编辑动态",
            placeholder="请输入动态，每行一个",
            current_text=self.user_activities,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_activities = dialog.get_text()
            self.activity_button.setText("编辑动态（已编辑）")
            print(f"动态已更新: {self.user_activities}")

    def edit_activity_img(self):
        dialog = EditTextDialog(
            title="编辑动态图片",
            placeholder="请输入动态图片路径，每行一个",
            current_text=self.user_activities_img,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_activities_img = dialog.get_text()
            self.activity_img_button.setText("编辑动态图片（已编辑）")
            print(f"动态已更新: {self.user_activities_img}")

    def edit_address(self):
        dialog = EditTextDialog(
            title="编辑地址",
            placeholder="请输入地址，每行一个",
            current_text=self.user_address,
            parent=self
        )
        if dialog.exec_() == QDialog.Accepted:
            self.user_address = dialog.get_text()
            self.address_button.setText("编辑地址（已编辑）")
            print(f"地址已更新: {self.user_address}")

    def get_switch_frequency(self):
        freq_text = self.switch_frequency_input.text().strip()
        if not freq_text:
            return 5
        try:
            freq = int(freq_text)
            if freq <= 0:
                raise ValueError
            return freq
        except ValueError:
            QMessageBox.warning(self, "输入错误", "切换频率必须是一个正整数。")
            return -1

    def collect_config(self):
        config = {
            'use_api_captcha': self.api_captcha_radio.isChecked(),
            'yes_api_key': self.yes_api_key_input.text().strip(),
            'window_count': int(self.window_count_combo.currentText()) if hasattr(self, 'window_count_combo') else 1,
            'save_location': self.save_location_input.text().strip(),
            'send_messages': self.send_msg_checkbox.isChecked(),
            'num_messages': int(self.num_msgs_combo.currentText()) if self.send_msg_checkbox.isChecked() else 0,
            'quick_registration': self.quick_reg_checkbox.isChecked(),
            # 'upload_images': self.upload_image_checkbox.isChecked(),
            # 'image_paths': [path.strip() for path in self.image_paths_input.text().split(',') if
            #                 path.strip()] if self.upload_image_checkbox.isChecked() else [],
            'use_bit_browser': self.use_bit_checkbox.isChecked(),
            'bit_port': int(
                self.port_input.text().strip()) if self.use_bit_checkbox.isChecked() and self.port_input.text().strip().isdigit() else 0,
            'use_system_chrome': self.use_chrome_checkbox.isChecked(),
            'chrome_path': self.chrome_path_input.text().strip() if self.use_chrome_checkbox.isChecked() else '',
            'proxy_type': self.proxy_combo.currentText(),
            'clash_port': int(
                self.clash_port_input.text().strip()) if self.proxy_combo.currentText() == 'Clash代理' and self.clash_port_input.text().strip().isdigit() else 0,
            'clash_node_names': [name.strip() for name in self.clash_node_names.splitlines() if
                                 name.strip()] if self.proxy_combo.currentText() == 'Clash代理' else [],
            'switch_frequency': self.get_switch_frequency(),
            'proxy_rule': self.proxy_rule_combo.currentText() if self.proxy_combo.currentText() == 'Clash代理' else '',
            'user_name_list': [name.strip() for name in self.user_names.splitlines() if name.strip()],
            'user_profile_list': [profile.strip() for profile in self.user_profiles.splitlines() if profile.strip()],
            'activity_enabled': self.activity_checkbox.isChecked(),
            'activity_img_enabled': self.activity_img_checkbox.isChecked(),
            'user_activity_list': [activity.strip() for activity in self.user_activities.splitlines() if
                                   activity.strip()],
            'user_activity_img_list': [activity_img.strip() for activity_img in self.user_activities_img.splitlines() if
                                       activity_img.strip()],
            'user_address_list': [address.strip() for address in self.user_address.splitlines() if address.strip()],
            'email_list': [line.strip() for line in self.line_str_input.toPlainText().splitlines() if line.strip()],
            'email_type': self.email_type_combo.currentText(),
            'custom_email_config': {
                'token': self.token_input.text().strip(),
                'default_password': self.default_password_input.text().strip(),
                'total_count': self.total_count_input.text().strip(),
                'email_host': self.email_host_input.text().strip(),
                'email_pop_host': self.email_pop_host_input.text().strip(),
                'email_pop_prot': self.email_pop_prot_input.text().strip(),

            } if self.email_type_combo.currentText() == '自建邮箱' else None,
            'name_suffix': {
                'enabled': self.name_suffix_checkbox.isChecked(),
                'content': self.suffix_content_input.text().strip(),
                'length': int(
                    self.suffix_length_input.text()) if self.suffix_length_input.text().strip().isdigit() else 4
            },
            'search_user_enabled': self.search_user_checkbox.isChecked(),
            'search_user_config': {
                'browse_users_count': int(self.browse_users_count.currentText()),
                'browse_users_name': self.browse_users_name.text(),
                'browse_times': int(self.browse_times.currentText()),
                'browse_duration': int(self.browse_duration.currentText())
            },
            'upload_avatar_enabled': self.upload_avatar_checkbox.isChecked(),
            'upload_background_enabled': self.upload_background_checkbox.isChecked(),
            'avatar_images': [img.strip() for img in self.user_avatar_images.splitlines() if
                              img.strip()] if self.upload_avatar_checkbox.isChecked() else [],
            'background_images': [img.strip() for img in self.user_background_images.splitlines() if
                                  img.strip()] if self.upload_background_checkbox.isChecked() else [],
        }
        return config

    def on_email_type_changed(self, index):
        if self.email_type_combo.currentText() == 'Outlook' or self.email_type_combo.currentText() == 'Firstmail' :
            self.custom_email_config.hide()
            self.line_str_input.show()
            self.line_str_label.show()
        else:
            self.custom_email_config.show()
            self.line_str_input.hide()
            self.line_str_label.hide()

    def save_config(self):
        config = self.collect_config()

        if not config['yes_api_key']:
            QMessageBox.warning(self, "输入错误", "请填写打码 API Key。")
            return

        if config['send_messages'] and config['num_messages'] <= 0:
            QMessageBox.warning(self, "输入错误", "请填写要发送的消息条数。")
            return

        # if config['upload_images'] and not config['image_paths']:
        #     QMessageBox.warning(self, "输入错误", "请选择要上传的图片文件。")
        #     return

        if config['proxy_type'] == 'Clash代理' and not config['clash_node_names']:
            QMessageBox.warning(self, "输入错误", "请编辑 Clash 节点名称。")
            return

        if config['proxy_type'] == 'Clash代理' and config['switch_frequency'] <= 0:
            QMessageBox.warning(self, "输入错误", "请填写有效的切换频率（正整数）。")
            return

        if config['use_system_chrome'] and not config['chrome_path']:
            QMessageBox.warning(self, "输入错误", "请选择系统 Chrome 浏览器的路径。")
            return

        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=4)
            print(f"配置已自动保存到 {self.config_file}")
        except Exception as e:
            QMessageBox.critical(self, "保存失败", f"保存配置时出错: {e}")

    def load_config_on_startup(self):
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    loaded_config = json.load(f)

                self.config = loaded_config

                use_api_captcha = loaded_config.get('use_api_captcha', False)
                self.api_captcha_radio.setChecked(use_api_captcha)
                self.local_captcha_radio.setChecked(not use_api_captcha)
                self.toggle_api_options(use_api_captcha)
                self.yes_api_key_input.setText(self.config.get('yes_api_key', ''))
                self.window_count_combo.setCurrentText(str(self.config.get('window_count', '1')))
                self.save_location_input.setText(self.config.get('save_location', ''))
                self.send_msg_checkbox.setChecked(self.config.get('send_messages', False))
                if self.send_msg_checkbox.isChecked():
                    self.num_msgs_combo.setDisabled(False)
                    self.num_msgs_combo.setCurrentText(str(self.config.get('num_messages', '1')))
                else:
                    self.num_msgs_combo.setDisabled(True)
                    self.num_msgs_combo.setCurrentText("1")

                self.quick_reg_checkbox.setChecked(self.config.get('quick_registration', False))
                if self.quick_reg_checkbox.isChecked():
                    self.send_msg_checkbox.setChecked(False)
                    self.send_msg_checkbox.setDisabled(True)
                else:
                    self.send_msg_checkbox.setDisabled(False)

                # 加载动态和动态图片的配置
                self.activity_checkbox.setChecked(self.config.get('activity_enabled', False))
                self.activity_img_checkbox.setChecked(self.config.get('activity_img_enabled', False))

                # 更新按钮状态
                self.toggle_activity_button(self.activity_checkbox.isChecked())

                # activity_button
                self.toggle_activity_img_button(self.activity_img_checkbox.isChecked())

                self.search_user_checkbox.setChecked(self.config.get('search_user_enabled', False))
                if self.config.get('search_user_config'):
                    self.browse_users_count.setCurrentText(
                        str(self.config['search_user_config'].get('browse_users_count', '0')))
                    self.browse_users_name.setText(
                        self.config['search_user_config'].get('browse_users_name', ''))
                    self.browse_times.setCurrentText(
                        str(self.config['search_user_config'].get('browse_times', '1')))
                    self.browse_duration.setCurrentText(
                        str(self.config['search_user_config'].get('browse_duration', '1')))

                # 更新控件状态
                self.toggle_search_user_options(self.search_user_checkbox.isChecked())

                # 加载头像和背景图配置
                self.upload_avatar_checkbox.setChecked(self.config.get('upload_avatar_enabled', False))
                self.upload_background_checkbox.setChecked(self.config.get('upload_background_enabled', False))

                self.user_avatar_images = '\n'.join(self.config.get('avatar_images', []))
                self.user_background_images = '\n'.join(self.config.get('background_images', []))

                # 更新按钮状态
                self.toggle_avatar_button(self.upload_avatar_checkbox.isChecked())
                self.toggle_background_button(self.upload_background_checkbox.isChecked())

                if self.user_avatar_images:
                    self.avatar_button.setText("编辑头像（已编辑）")
                if self.user_background_images:
                    self.background_button.setText("编辑背景图（已编辑）")

                self.use_bit_checkbox.setChecked(self.config.get('use_bit_browser', False))
                if self.use_bit_checkbox.isChecked():
                    self.port_input.setDisabled(False)
                    self.port_input.setText(str(self.config.get('bit_port', '54345')))
                else:
                    self.port_input.setDisabled(True)
                    self.port_input.clear()

                self.use_chrome_checkbox.setChecked(self.config.get('use_system_chrome', False))
                if self.use_chrome_checkbox.isChecked():
                    self.chrome_path_input.setDisabled(False)
                    self.browse_chrome_button.setDisabled(False)
                    self.chrome_path_input.setText(self.config.get('chrome_path', ''))
                else:
                    self.chrome_path_input.setDisabled(True)
                    self.browse_chrome_button.setDisabled(True)
                    self.chrome_path_input.clear()

                self.proxy_combo.setCurrentText(self.config.get('proxy_type', '本地代理'))
                self.on_proxy_selection_changed(self.proxy_combo.currentIndex())

                if self.config.get('proxy_type') == 'Clash代理':
                    self.clash_port_input.setText(str(self.config.get('clash_port', '7890')))
                    self.clash_node_names = '\n'.join(self.config.get('clash_node_names', []))
                    self.switch_frequency_input.setText(str(self.config.get('switch_frequency', '5')))
                    self.proxy_rule_combo.setCurrentText(self.config.get('proxy_rule', 'Proxy'))

                self.user_names = '\n'.join(self.config.get('user_name_list', []))
                self.user_profiles = '\n'.join(self.config.get('user_profile_list', []))
                self.user_activities = '\n'.join(self.config.get('user_activity_list', []))
                self.user_activities_img = '\n'.join(self.config.get('user_activity_img_list', []))
                self.user_address = '\n'.join(self.config.get('user_address_list', []))

                # 加载姓名后缀配置
                self.name_suffix_checkbox.setChecked(self.config.get('enabled', False))
                self.suffix_content_input.setText(self.config.get('content', ''))
                self.suffix_length_input.setText(str(self.config.get('length', 4)))
                if self.user_names:
                    self.name_button.setText("编辑姓名（已编辑）")
                if self.user_profiles:
                    self.profile_button.setText("编辑简介（已编辑）")
                if self.user_activities:
                    self.activity_button.setText("编辑动态（已编辑）")
                if self.user_activities_img:
                    self.activity_img_button.setText("编辑动态图片（已编辑）")
                if self.user_address:
                    self.address_button.setText("编辑地址（已编辑）")

                # 加载邮箱类型配置
                self.email_type_combo.setCurrentText(self.config.get('email_type', 'Outlook'))
                if self.config.get('custom_email_config'):
                    self.token_input.setText(self.config['custom_email_config'].get('token', ''))
                    self.default_password_input.setText(self.config['custom_email_config'].get('default_password', ''))
                    self.total_count_input.setText(self.config['custom_email_config'].get('total_count', '1000'))
                    self.email_host_input.setText(self.config['custom_email_config'].get('email_host', ''))
                    self.email_pop_host_input.setText(self.config['custom_email_config'].get('email_pop_host', ''))
                    self.email_pop_prot_input.setText(self.config['custom_email_config'].get('email_pop_prot', ''))

                email_list = self.config.get('email_list', [])
                self.line_str_input.setText('\n'.join(email_list))

                print(f"配置已自动加载自 {self.config_file}")
            except Exception as e:
                QMessageBox.critical(self, "加载失败", f"加载配置时出错: {e}")
        else:
            print("配置文件不存在，使用默认配置。")

    def _handle_proxy_switch(self, idx):
        """处理代理切换"""
        if self.proxy_rotator and (idx + 1) % self.config['switch_frequency'] == 0:
            switch_result = self.proxy_rotator.switch_to_next_proxy()
            if switch_result['success']:
                self.log_text.append(
                    f"已切换到代理节点：{self.proxy_rotator.node_names[self.proxy_rotator.current_node_index]['name']}"
                )
            else:
                self.log_text.append(f"切换代理失败：{switch_result['error']}")

    def _create_and_start_worker(self, email_or_line, identifier):
        """创建并启动工作线程"""
        chrome_path = self.config.get('chrome_path', '') if self.config.get('use_system_chrome') else None

        runnable = WorkerRunnable(
            self.config.copy(),
            email_or_line,
            identifier,
            proxy_rotator=self.proxy_rotator,
            chrome_path=chrome_path,
            parent=self
        )
        runnable.signals.log.connect(self.update_log)
        runnable.signals.finished.connect(self.thread_finished)
        runnable.signals.update_gui.connect(self.update_gui_content)  # 连接新的信号
        self.threadpool.start(runnable)
        self.active_runnables.append(runnable)

    def start_test(self):
        config = self.collect_config()

        if not config['yes_api_key']:
            QMessageBox.warning(self, "输入错误", "请填写打码 API Key。")
            return
        # 验证自建邮箱配置
        if config['email_type'] == '自建邮箱':
            if not config['custom_email_config'].get('token'):
                QMessageBox.warning(self, "输入错误", "请填写Token。")
                return
            if not config['custom_email_config'].get('email_host'):
                QMessageBox.warning(self, "输入错误", "请填写email_host。")
                return
            if not config['custom_email_config'].get('email_pop_host'):
                QMessageBox.warning(self, "输入错误", "请填写pop地址。")
                return
            if not config['custom_email_config'].get('email_pop_prot'):
                QMessageBox.warning(self, "输入错误", "请填写port。")
                return
            try:
                total_count = int(config['custom_email_config'].get('total_count', '1000'))
                if total_count <= 0:
                    QMessageBox.warning(self, "输入错误", "任务总数必须大于0。")
                    return
            except ValueError:
                QMessageBox.warning(self, "输入错误", "任务总数必须是有效的数字。")
                return
        else:
            # 邮箱验证
            line_str = self.line_str_input.toPlainText().strip()
            if not line_str:
                QMessageBox.warning(self, "输入错误", "请填写邮箱列表。")
                return
            self.line_strs = [line.strip() for line in line_str.splitlines() if line.strip()]
        if config['send_messages'] and config['num_messages'] <= 0:
            QMessageBox.warning(self, "输入错误", "请填写要发送的消息条数。")
            return

        if config['proxy_type'] == 'Clash代理' and not config['clash_node_names']:
            QMessageBox.warning(self, "输入错误", "请编辑 Clash 节点名称。")
            return

        if config['proxy_type'] == 'Clash代理' and config['switch_frequency'] <= 0:
            QMessageBox.warning(self, "输入错误", "请填写有效的切换频率（正整数）。")
            return

        if config['use_system_chrome'] and not config['chrome_path']:
            QMessageBox.warning(self, "输入错误", "请选择系统 Chrome 浏览器的路径。")
            return

        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)
        self.log_text.append("测试开始...")
        self.logs = []
        self.is_stopped = False

        self.config = config
        self.save_config()

        self.proxy_rotator = None
        if self.config.get('proxy_type') == 'Clash代理':
            clash_port = self.config.get('clash_port', 7890)
            clash_api_port = clash_port + 3
            api_url = f"http://127.0.0.1:{clash_api_port}"
            selector_name = self.config.get('proxy_rule', 'Proxy')
            node_names = self.config.get('clash_node_names', [])
            self.proxy_rotator = ClashProxyRotator(api_url, selector_name, node_names)

        window_count = self.config.get('window_count', 1)
        self.threadpool.setMaxThreadCount(window_count)
        print(f"设置线程池的最大并发数为: {window_count}")

        # 主逻辑
        if config['email_type'] == '自建邮箱':
            # 自建邮箱模式
            total_count = int(config['custom_email_config'].get('total_count', '1000'))

            for idx in range(total_count):
                if self.is_stopped:
                    break

                random_username = generate_random_string(10)

                # 解析 URL
                parsed_url = urlparse(self.email_host_input.text())
                extracted = tldextract.extract(parsed_url.netloc)
                main_domain = f"{extracted.domain}.{extracted.suffix}"
                email = f"{random_username}@{main_domain}"

                token = config['custom_email_config']['token']
                default_password = config['custom_email_config'].get('default_password', '')
                if not default_password:
                    default_password = generate_random_string(10)

                identifier = f"账号{idx + 1}"
                line_str = f"{email}----{default_password}----{token}"

                self._create_and_start_worker(line_str, identifier)
                self._handle_proxy_switch(idx)

        else:
            # Outlook邮箱模式
            for idx, ls in enumerate(self.line_strs):
                if self.is_stopped:
                    break

                try:
                    identifier = ls.split('----')[0]
                except IndexError:
                    identifier = f"账号{idx + 1}"

                self._create_and_start_worker(ls, identifier)
                self._handle_proxy_switch(idx)

    def update_log(self, identifier, message):
        timestamp = datetime.datetime.now().strftime("[%Y-%m-%d %H:%M:%S]")
        log_entry = f"{timestamp} [{identifier}] {message}"
        self.log_text.append(log_entry)
        self.logs.append(log_entry)

    def thread_finished(self, identifier, success):
        if success:
            status = "成功"
        else:
            status = "失败"
        self.log_text.append(f"账号 {identifier} 测试{status}。")

        self.active_runnables = [r for r in self.active_runnables if r._is_running]

        if len(self.active_runnables) == 0:
            self.log_text.append("所有账号已处理完毕。")
            self.start_button.setEnabled(True)
            self.stop_button.setEnabled(False)

    def stop_test(self):
        self.is_stopped = True
        for runnable in self.active_runnables:
            runnable.stop()
        self.active_runnables.clear()

        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.log_text.append("测试已手动停止。")

    def save_config_on_exit(self):
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.collect_config(), f, ensure_ascii=False, indent=4)
            print(f"配置已自动保存到 {self.config_file}")
        except Exception as e:
            print(f"自动保存配置时出错: {e}")

    def closeEvent(self, event):
        self.save_config_on_exit()
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("icon.ico"))
    demo = AppDemo()

    demo.show()
    sys.exit(app.exec_())
